const Cons = require('./constants');
const ipcModel = require('../models/ipc.model');
const classcampusModel = require('../models/classcampus.model');
const classattendanceModel = require('../models/class_attendance.model')

const userModel = require('../models/user.model');
const ipcUrl = require('../../config/global_config').ipc;
const httpUtil = require('../utils/http');
const logger = require('../utils/logger');
const globalConfig = require('../../config/global_config');

// 清空所有巨龙设备-底库信息
async function emptyAllDeviceLibrary(){
    const isDev = false
    // 校验参数
    let allDevices = await ipcModel.find({d_tp:Cons.IPC_TYPE_jHD23})
    if(allDevices&&allDevices.length===0){
        return logger.logInfo("\n" + '===== 无可用设备 =====' + "\n");
    }
    let defaultTryTimes = 3
    async function emptyFn(devices,tryTimes){
        let needTryDevices = []
        for(let device of devices){
            const queryParams = {
                Name: 'personListRequest',
                Session:device.register_session,
                TimeStamp:Math.floor(+new Date()/1000),
                UUID:device.device_uuid,
                ip:device.device_ip,
                Data:{
                    Action:'deletePersonList',
                    PersonType:2,
                }
            }
            try{
                const res = await httpUtil.postWithTimeout(`http://${isDev?queryParams.ip:'127.0.0.1'}:8011/Request`,queryParams, 1000*20, '设备连接超时')
                if(res && res.Code === 1) {
                    console.log(`${device.d_nm}(${device.device_num})清空成功`)
                }else{
                    // console.log(`====设备${device.d_nm}(${device.device_num})：清空底库失败，${res.msg||'设备异常'} ==== \n ===== ${remainTimes?`还会重试${remainTimes}次`:'不再重试'}=====`)
                    logger.logError(`====设备${device.d_nm}(${device.device_num})：清空底库失败，${res.msg||'设备异常'} ==== \n ===== ${remainTimes?`还会重试${remainTimes}次`:'不再重试'}=====`)
                    needTryDevices.push(device)
                }
            }catch(err){
                var remainTimes = tryTimes-1
                logger.logError(`====设备${device.d_nm}(${device.device_num})：清空底库失败，原因连接异常 ==== \n ===== ${remainTimes?`还会重试${remainTimes}次`:'不再重试'}=====`)
                needTryDevices.push(device)
            }
        }
        if(needTryDevices.length>0){
            if(--tryTimes>0){
                emptyFn(needTryDevices,tryTimes)
            }else{
                const errorDeviceMap = needTryDevices.map(item=>{
                    return `${item.d_nm}(${item.device_num})`
                })
                // console.log('以下设备清空失败',errorDeviceMap.join(','))
                logger.logError("\n" + '===== 以下设备清空失败 ===== ' + "\n"  + "====" + errorDeviceMap.join('\n') + '=====' + "\n");
            }
        }else{
            // console.log('所有设备清空成功')
            logger.logInfo("\n" + '===== 所有设备清空成功 =====' + "\n");
        }
    }
    emptyFn(allDevices,defaultTryTimes)
}

// 清空课表信息
async function clearAttendanceList(timeStamp){
    timeStamp = timeStamp || new Date().setHours(0,0,0,0)
    try{
        await classattendanceModel.remove({
            attendance_start_date:{
                $lt: timeStamp
            }
        })
        logger.logInfo(`\n ==== 清空考勤表 ==== \n`)
    }catch(err){
        logger.logError(`\n ==== 清空考勤表失败 ==== \n`)
    }
}

// 校区请求token
async function getCampusToken(item,times){
    try{
        let key = Buffer.from(`${item.campus_id}:${item.secret}`).toString('base64')
        const res = await httpUtil.post(`${globalConfig.jiayiServer}/oauth/token?grant_type=client_credentials`,{},{
            headers:{
                Authorization:`Basic ${key}`
            }
        })
        if(res.code===0){
            const resData = res.data
            await classcampusModel.updateOne({_id:item._id},{
                access_token:resData.access_token,
                token_type:resData.token_type,
                expires_in:resData.expires_in,
                scope:resData.scope
            })
            console.log(`校区：${item.campus_id}，获取token成功`)
            logger.logInfo(`校区：${item.campus_id}，获取token成功`)
            return resData.access_token
        }else{
            times--
            if(times>0){
                console.log(`校区：${item.campus_id}，获取token失败，还会尝试${times}次`)
                logger.logInfo(`校区：${item.campus_id}，获取token成功，还会尝试${times}次`)
                return getCampusToken(item,times)
            }        
        }
    }catch(err){
        console.log(err)
        times--
        if(times>0){
            console.log(`校区：${item.campus_id}，获取token失败，还会尝试${times}次`)
            logger.logInfo(`校区：${item.campus_id}，获取token成功，还会尝试${times}次`)
            return getCampusToken(item,times)
        }
    }
}

// 获取授权
async function getAuthInfo(){
    const campusList = await classcampusModel.find()
    if(campusList&&campusList.length){
        for(let item of campusList){
            let itemryTimes = 3
            await getCampusToken(item,itemryTimes)
        }
    }
}

// 每日任务：请求第二天上课信息接口
async function getNextDayClass(){
    try{
        const allCampus = await classcampusModel.find({
            access_token:{
                $ne: ''
            }
        })
        for(let campusItem of allCampus){
            await getDayCampusInfo(campusItem)
        }
    }catch(err){
        console.log(err)
    }
}

// 保存处理每个校区下的上课信息
async function getDayCampusInfo(campusItem){
    // 校区基本信息
    const baseInfo = {
        group_id: campusItem.group_id,
        group_name: campusItem.group_name,
        campus_id: campusItem.campus_id,
        campus_name: campusItem.campus_name
    }
    const res = await httpUtil.get(`${globalConfig.jiayiServer}/affairsUser/getAllStuInfoByAdmissionAmpus?access_token=${campusItem.access_token}`)
    if(res.code===0){
        const allData = res.data||[]
        const libraryData = []
        for(let classItem of allData){
            
            // 待存底库的学生信息项，以摄像头id为标示
            let campusLibraryItem = Object.assign({},baseInfo); 

            // 临时学生id集合防止重复；准备存底库的学生集合
            let tempStudentIds = [],studentInfoAry = []; 

            //  生成考勤表,以班级为单位
            let student_collection = classItem.studentInfoList.map(item=>{
                if(tempStudentIds.indexOf(item.studentId)===-1){
                    // 保存学生信息
                    const studentParams = Object.assign({},baseInfo,{
                        s_id:item.studentId,
                        u_nm:item.studentName,
                        s_avatar_url:item.photo,
                        u_tp: 5, //学生
                        // class_id:classItem.classId, //可能学生当前有多个班级课，先不保存
                        // class_name:classItem.className
                    })
                    saveStudentInfo(studentParams)

                    // 收集存底库的校区学生集合
                    tempStudentIds.push(item.id)
                    studentInfoAry.push({
                        student_id: item.studentId,
                        // student_name: item.studentName,
                        // student_num: item.studentNum,
                        student_avatar: item.photo,
                    })
                    // 格式化校区学生信息
                    return {
                        student_id: item.studentId,
                        // student_name: item.studentName,
                        // student_num: item.studentNum,
                        student_avatar: item.photo,
                        attendance_start_time:'',
                        attendance_end_time:''
                    }
                }
            }).filter(Boolean)


            let attendanceItem = Object.assign({},baseInfo,{
                class_id: classItem.classId,
                // class_name: classItem.className,
                classroom_id: classItem.classroomId,
                lession_id: classItem.lessonId,
                attendance_start_date: new Date(+classItem.startTime).setHours(0,0,0,0),
                attendance_end_date: new Date(+classItem.startTime).setHours(23,59,59),
                class_start_time: classItem.startTime,
                class_end_time: classItem.endTime,
                student_collection,
                device_collection: (classItem.device_ids||[]).map(child=>({
                    device_id:child,
                    // device_name:'',
                    // device_num:''
                }))
            })
            // 保存考勤表
            const checkItem = await classattendanceModel.findOne({lession_id:classItem.lession_id})
            if(!checkItem){
                await classattendanceModel.create(attendanceItem)
                console.log(checkItem)
            }else{
                console.log(`课次id：${classItem.lession_id}已存在，请检查`)
            }

            // 汇总收集入底库的学生信息
            campusLibraryItem.student_info = studentInfoAry
            if(classItem.device_ids&&classItem.device_ids.length){
                classItem.device_ids.forEach(id=>{
                    libraryData.push(Object.assign({},{...campusLibraryItem},{
                        classroom_id: classItem.classroomId,
                        device_id:id
                    }))
                })
            }
            // libraryData.push(campusLibraryItem)
        }   
        // 保存学生信息到底库
        if(libraryData.length){
            saveStudentToLibrary(libraryData)
        }
    }else{

    }
}

// 保存学生信息
async function saveStudentInfo(data){
    try{
       const student = await userModel.findOne({s_id:data.s_id})
       if(student){
           return logger.logError(`===== 学生id：${data.s_id} 已存在 =====`)
       }
       await userModel.create(data)
       logger.logInfo(`===== 学生id：${data.s_id} 添加成功 =====`)
    }catch(err){
        logger.logError(`===== 学生id：${data.s_id} 添加失败 =====`)
    }
}

// 清空学生信息
async function clearStudentInfo(){
    try{
        await userModel.remove({u_tp:5})
        logger.logInfo(`\n ==== 清空学生信息成功 ==== \n `)
    }catch(err){
        logger.logError(`\n ==== 清空学生信息失败 ==== \n `)
    }
}

// 保存照片到底库
async function saveStudentToLibrary(allData){
    for(let item of allData){
        // 根据校区同步设备
        const device = await ipcModel.findOneAndUpdate({
            _id:item.device_id,
            device_uuid:{$ne:null},
            register_session:{$ne:null},
            group_id: item.group_id,
            group_name: item.group_name,
            campus_id: item.campus_id,
            campus_name: item.campus_name,
            classroom_id: item.classroom_id
        })
        if(!device){
            console.log(`\n ==== 设备id：${item.device_id} 不存在或者未完成注册==== \n `)
            logger.logError(`\n ==== 设备id：${item.device_id} 不存在或者未完成注册==== \n `)
        }
        const student_info = item.student_info
        for(let student of student_info){
            const studentAvatar = student.student_avatar
            const base64Avatar = await onlineImgTo64(studentAvatar)
            if(base64Avatar) {
                const studentParams = {
                    Name:'personListRequest',
                    UUID:device.device_uuid,
                    ChannelNo: device.channel_num,
                    Session: device.register_session,
                    TimeStamp:Math.floor(+new Date()/1000),
                    Sign:'',
                    Data:{
                        Action:'addPerson',
                        PersonType:2,
                        PersonInfo:{
                            PersonId: student.student_id,
                            // PersonName: student.student_name,
                            PersonExtension:{
                                // PersonCode1: student.student_num,
                            },
                            PersonPhoto: base64Avatar
                        },
                    },
                }
                await saveStudentToDevice(studentParams,device,3)
            }      
        }
    }
}

// 在线图片转base64
async function onlineImgTo64(url){
    if(!url){
        return
    }
    try{
        console.log(url)
        const base64Img = await httpUtil.get(url,{},{
            encoding:'base64'
        })
        // const fs = require('fs')
        // const imgBuffer = Buffer.from(base64Img,'base64')
        // fs.writeFileSync('test.png',imgBuffer)
        return base64Img

    }catch(err){
        console.log(`\n ==== 图片-${url}：下载或处理失败，请检查 ==== \n`)
        logger.logError(`\n ==== 图片-${url}：下载或处理失败，请检查 ==== \n`)
    }
}

// 保存图片到设备底库
async function saveStudentToDevice(studentParams,device,tryTimes){
    try{
        const res = await httpUtil.postWithTimeout(`http://127.0.0.1:8011/Request`,studentParams,1000*20)
        let formatRes = formatSaveRes(res,device)
        if(!formatRes){
            console.log(`设备-${device.d_nm}(${device.device_num}) --- 学员：${student.student_id} 保存底库成功`)
        }else if(formatRes.isTimeout){
            // 超时
            --tryTimes
            logger.logError(`\n ==== 设备-${device.d_nm}(${device.device_num})-保存超时 ==== \n`)
            if(tryTimes>0){
                saveStudentToDevice(studentParams,device,tryTimes)
            }
        }else if(formatRes.isExist){
            // 编辑
            logger.logError(`\n ==== 设备-${device.d_nm}(${device.device_num})-${student.student_id}底库已存在 ==== \n`)
        }else{
            --tryTimes
            logger.logError(`\n ==== 错误信息：${formatRes.errMsg} ==== \n`)
            if(tryTimes>0){
                saveStudentToDevice(studentParams,device,tryTimes)
            }
        }
    }catch(err){
        --tryTimes
        // console.log(`\n ==== 设备-${device.d_nm}(${device.device_num})- 请求异常 ==== \n`)
        logger.logError(`\n ==== 设备-${device.d_nm}(${device.device_num})- 请求异常 ==== \n`)
        if(tryTimes>0){
            saveStudentToDevice(studentParams,device,tryTimes)
        }
    }
}


// 格式化图片存底库结果
function formatSaveRes(res,device){
    let isError=false,isExist=false,isTimeout=false,errMsg='';
    if(res.Code===1){
        return isError
    }else if(res.Code===2){
        isTimeout = true
    }else if(res.Code === 1110 && res.Data.Result === -3){
        // 文件名字编号重复，新增操作时才会出现的错误码
        isExist = true
    }else if(res.Code === 1110 && res.Data.Result === -7){
        isError = true
        errMsg+=`设备-${device.d_nm}(${device.device_num})文件过大;`
    }else if(res.Code === 1110 && res.Data.Result === -8){
        isError = true
        errMsg+=`设备-${device.d_nm}(${device.device_num})储存空间不足;`
    }else if(res.Code === 1110 && res.Data.Result === -13){
        isError = true
        errMsg+=`设备-${device.d_nm}(${device.device_num})图片质量差;`
    }else if(res.Code === 1110 && res.Data.Result === -15){
        isError = true
        errMsg+=`设备-${device.d_nm}(${device.device_num})检测人脸失败;`
    }else {
        isError = true
        errMsg+=`设备-${device.d_nm}(${device.device_num})保存失败;`
    }
    return {
        isError,
        isExist,
        isTimeout,
        errMsg
    }
}

// 返回考勤结果
async function getAttendanceDetail(lesson_id){
    const attendanceDetail = await classattendanceModel.findOne({
        lesson_id
    })
    return attendanceDetail
}

// 推送考勤消息
async function sendAttendanceInfo(careUnCompleted=true,dateStamp=0,finishMinutes=5){
    const zeroTimeStamp = new Date().setHours(0,0,0,0)
    const boundaryTimeStamp = Date.now()-finishMinutes*60*1000 //边界时间，默认当前时间达到上课结束后的五分钟
    const queryParams = {
        attendance_start_date: zeroTimeStamp
    }
    if(careUnCompleted){
        // 是否关注成功推送过消息的，默认关注；即只推送尚未推送过的考勤信息
        queryParams.is_completed = 0
    }
    if(dateStamp){
        // 考勤时间，默认只关注当天的日期
        queryParams.attendance_start_date =  dateStamp
    }
    if(finishMinutes){
        // 消息推送标准，默认上课结束五分钟之后的
        queryParams.class_end_time = {
            $lte:boundaryTimeStamp
        }
    }
    const allClassattendance = await classattendanceModel.find(queryParams)
    for(let classItem of allClassattendance){
        sendAttendanceItem(classItem,3)
    }
}

// 推送到佳一后台
async function sendAttendanceItem(item,tryTimes){
    try{
        const sendParams = {
            classId:item.class_id,
            lessonId:item.lesson_id
        }
        const campusItem = await classcampusModel.findOne({
            campus_id:item.campus_id
        })
        if(!campusItem){
            console.log(`\n ==== 校区ID：${item.campus_id} 未再百家云系统中找到，请检查或新增 ==== \n`)
            return logger.logError(`\n ==== 校区ID：${item.campus_id} 未再百家云系统中找到，请检查或新增 ==== \n`)
        }
        if(!campusItem.access_token){
            const accessToken = await getCampusToken(campusItem,3)
            if(!accessToken){
                console.log(`\n ==== 校区ID：${item.campus_id} 获取授权失败，请重试 ==== \n`)
                return logger.logError(`\n ==== 校区ID：${item.campus_id} 获取授权失败，请重试 ==== \n`)
            }
            sendParams.access_token = accessToken
        }else{
            sendParams.access_token = campusItem.access_token
        }
        const studentIds = item.student_collection.map(item=>{
            if(item.attendance_start_time){
                return item.student_id
            }
        }).filter(Boolean)
        sendParams.studentIdList = studentIds

        const res = await httpUtil.post(`${globalConfig.jiayiServer}/attendance/faceRecognitoin`,sendParams)
        if(res.code===0){
            // 发送成功标记
            await classattendanceModel.findOneAndUpdate({lesson_id:item.lesson_id},{is_completed:1})
        }else{
            --tryTimes
            logger.logError(`\n ==== ${item.class_name} 发送考勤消息失败，${tryTimes?`还会尝试${tryTimes}次`:'不会再尝试'} ====\n`)
            // console.log(`\n ==== ${item.class_name} 发送考勤消息失败，${tryTimes?`还会尝试${tryTimes}次`:'不会再尝试'}====\n`)
            if(tryTimes>0){
                sendAttendanceItem(item,tryTimes)
            } 
        }
    }catch(err){
        --tryTimes
        logger.logError(`\n ==== ${item.class_name} 发送考勤消息失败，${tryTimes?`还会尝试${tryTimes}次`:'不会再尝试'} ====\n`)
        // console.log(`\n ==== ${item.class_name} 发送考勤消息失败，${tryTimes?`还会尝试${tryTimes}次`:'不会再尝试'}====\n`)
        if(tryTimes>0){
            sendAttendanceItem(item,tryTimes)
        }
    }
}

module.exports = {
    emptyAllDeviceLibrary,
    clearAttendanceList,
    clearStudentInfo,
    getNextDayClass,
    sendAttendanceInfo
}